package site.codeyin.javautils.controller;

import com.alibaba.excel.util.ListUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import site.codeyin.javautils.constant.BizConstant;
import site.codeyin.javautils.constant.RedisKeyConstant;
import site.codeyin.javautils.controller.aspect.spel.Spel;
import site.codeyin.javautils.controller.excel.DownloadData;
import site.codeyin.javautils.controller.excel.ExcelUtils;
import site.codeyin.javautils.controller.req.*;
import site.codeyin.javautils.service.LockService;
import site.codeyin.javautils.utils.SpringContextUtils;
import site.codeyin.javautils.utils.filedownLoad.MultiThreadedDownloader;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author <a href="https://github.com/liangcheng2221">yinjie</a>
 * @date 2024-09-07 9:52
 */
@RestController
@RequestMapping("/utils")
@Validated
@Slf4j
public class UtilsController {

    @Resource
    private MultiThreadedDownloader downloader;

    @Resource(name = "redssion")
    private LockService redssionLockService;


    /**
     * excel导出功能
     *
     * @param servletResponse
     * @throws IOException
     */
    @PostMapping("/exportExcel")
    public void testExcel(HttpServletResponse servletResponse) throws IOException {
        ExcelUtils.writeWebResponseExcel(servletResponse, DownloadData.class, data(), "excel");
    }

    /**
     * 测试 @Validated 校验注解
     *
     * @param testReq
     */
    @PostMapping("/testValidated")
    public void testValidate(@RequestBody TestReq testReq) {
        log.info("testReq:{}", testReq);
    }

    /**
     * spel表达式测试
     *
     * @param spelReq
     */
    @PostMapping("/spel")
    @Spel("#spelReq")
    public void spel(@RequestBody SpelReq spelReq) {
        log.info("spelReq:{}", spelReq);
    }


    /**
     * 多线程下载文件
     *
     * @param downloadReq
     */
    @PostMapping("/multiDownload")
    public void multiDownload(@Validated @RequestBody DownloadReq downloadReq) {
        String serverPath = downloadReq.getUrl();
        Boolean flag = downloader.downloadFile(serverPath, BizConstant.LOCAL_FILE_PATH + new File(serverPath).getName());
        log.info("flag:{}", flag);
    }

    /**
     * 设置指定线程池设置线程池参数
     *
     * @param setThreadPoolReq 请求参数
     */
    @PostMapping("/setThreadPool")
    public void setThreadPool(@Validated @RequestBody SetThreadPoolReq setThreadPoolReq) {
        log.info("setThreadPoolReq:{}", setThreadPoolReq);
        ThreadPoolExecutor threadPoolExecutor = null;
        try {
            threadPoolExecutor = SpringContextUtils.getBean(setThreadPoolReq.getThreadPoolName(), ThreadPoolExecutor.class);
            threadPoolExecutor.setCorePoolSize(setThreadPoolReq.getCorePoolSize());
            threadPoolExecutor.setMaximumPoolSize(setThreadPoolReq.getMaximumPoolSize());
            threadPoolExecutor.setKeepAliveTime(setThreadPoolReq.getKeepAliveTime(), TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("设置线程池失败", e);
        }
    }

    /**
     * 查询指定线程池设置线程池参数
     *
     * @param getThreadPoolReq 请求参数
     */
    @PostMapping("/getThreadPool")
    public void getThreadPool(@Validated @RequestBody GetThreadPoolReq getThreadPoolReq) {
        log.info("setThreadPoolReq:{}", getThreadPoolReq);
        ThreadPoolExecutor threadPoolExecutor = null;
        try {
            threadPoolExecutor = SpringContextUtils.getBean(getThreadPoolReq.getThreadPoolName(), ThreadPoolExecutor.class);
        } catch (Exception e) {
            log.error("获取线程池失败", e);
            return;
        }

        log.info("corePoolSize:{}, maximumPoolSize:{}, keepAliveTime:{}, poolSize:{}, activeCount:{}"
                , threadPoolExecutor.getCorePoolSize()
                , threadPoolExecutor.getMaximumPoolSize()
                , threadPoolExecutor.getKeepAliveTime(TimeUnit.SECONDS)
                , threadPoolExecutor.getPoolSize()
                , threadPoolExecutor.getActiveCount());
    }

    /**
     * 获取分布式锁
     *
     * @param idempotentReq 请求参数
     */
    @PostMapping("/redissonLock")
    public void redissonLock(@Validated @RequestBody IdempotentReq idempotentReq) {
        log.info("idempotentReq:{}", idempotentReq);

        RLock rLock = null;
        try {
            rLock = redssionLockService.lock(RedisKeyConstant.IDEMPOTENT_KEY_PREFIX + idempotentReq.getIdempotentID()
                    , BizConstant.IDEMPOTENT_ID_EXPIRE_TIME
                    , BizConstant.LOCK_WAIT_TIME);
        } catch (Throwable e) {
            log.error("获取锁失败", e);
        }

        if (rLock != null) {
            log.info("获取锁成功");
        }

        log.info("模拟执行需要幂等控制的任务");

        Boolean unlock = redssionLockService.unlock(rLock);

        log.info("unlock:{}", unlock);


    }


    private List<DownloadData> data() {
        List<DownloadData> list = ListUtils.newArrayList();
        for (int i = 0; i < 10; i++) {
            DownloadData data = new DownloadData();
            data.setString("字符串" + 0);
            data.setDate(new Date());
            data.setDoubleData(0.56);
            list.add(data);
        }
        return list;
    }

}
